home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / devSCSITape.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  28.5 KB  |  1,051 lines

  1. /* 
  2.  * devSCSITape.c --
  3.  *
  4.  *      The standard Open, Read, Write, IOControl, and Close operations
  5.  *      are defined here for the SCSI tape.
  6.  *
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *
  15.  * Copyright 1986 Regents of the University of California
  16.  * All rights reserved.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devSCSITape.c,v 9.14 91/12/11 17:58:53 jhh Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <stdio.h>
  26. #include <fs.h>
  27. #include <dev.h>
  28. #include <devInt.h>
  29. #include <sys/scsi.h>
  30. #include <scsiDevice.h>
  31. #include <scsiTape.h>
  32. #include <devSCSITape.h>
  33. #include <dev/scsi.h>
  34. #include <stdlib.h>
  35. #include <bstring.h>
  36. #include <dbg.h>
  37. #include <mach.h>
  38.  
  39. int SCSITapeDebug = FALSE;
  40.  
  41. #define Min(a,b)  ((a) < (b) ? (a) : (b))
  42.  
  43. static ReturnStatus InitTapeDevice _ARGS_((Fs_Device *devicePtr,
  44.     ScsiDevice *devPtr));
  45. static void SetupCommand _ARGS_((ScsiDevice *devPtr, int command,
  46.     unsigned int code, unsigned int len, ScsiCmd *scsiCmdPtr));
  47. static ReturnStatus InitError _ARGS_((ScsiDevice *devPtr, ScsiCmd *scsiCmdPtr));
  48.  
  49.  
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * InitError --
  54.  *
  55.  *    Initial error proc used by InitTapeDevice when it is initializing
  56.  *    things for the real error handlers.  
  57.  *
  58.  * Results:
  59.  *    DEV_OFFLINE if the device is offline, SUCCESS otherwise.
  60.  *
  61.  * Side effects:
  62.  *    None.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66. /*ARGSUSED*/
  67. static ReturnStatus
  68. InitError(devPtr, scsiCmdPtr)
  69.     ScsiDevice     *devPtr;    /* SCSI device that's complaining. */
  70.     ScsiCmd    *scsiCmdPtr;    /* SCSI command that had the problem. */
  71. {
  72.     ScsiStatus         *scsiStatusPtr;
  73.     unsigned char    statusByte;
  74.     ScsiClass7Sense    *sensePtr;
  75.  
  76.     statusByte = (unsigned char) scsiCmdPtr->statusByte;
  77.     scsiStatusPtr = (ScsiStatus *) &statusByte;
  78.     if (!scsiStatusPtr->check) {
  79.     if (scsiStatusPtr->busy) {
  80.         return DEV_OFFLINE;
  81.     }
  82.     return SUCCESS;
  83.     }
  84.     sensePtr = (ScsiClass7Sense *) scsiCmdPtr->senseBuffer;
  85.     if (sensePtr->key == SCSI_CLASS7_NOT_READY) {
  86.     return DEV_OFFLINE;
  87.     }
  88.     if (sensePtr->key == SCSI_CLASS7_NO_SENSE) {
  89.     return SUCCESS;
  90.     }
  91.     return FAILURE;
  92. }
  93.  
  94. /*
  95.  *----------------------------------------------------------------------
  96.  *
  97.  * InitTapeDevice --
  98.  *
  99.  *    Initialize the device driver state for a SCSI Tape drive.
  100.  *
  101.  * Results:
  102.  *    SUCCESS.  If the tape driver is successfully initialized. A 
  103.  *    Sprite error code otherwise.
  104.  *
  105.  * Side effects:
  106.  *
  107.  *----------------------------------------------------------------------
  108.  */
  109. static ReturnStatus
  110. InitTapeDevice(devicePtr, devPtr)
  111.     Fs_Device *devicePtr;    /* Device info, unit number etc. */
  112.     ScsiDevice *devPtr;        /* Attached SCSI tape. */
  113. {
  114.     ScsiTape        tapeData;    
  115.     ScsiTape        *tapePtr;
  116.     ReturnStatus     status;
  117.     int            i;
  118.     ScsiInquiryData    *inquiryPtr;
  119.     int            min;
  120.     int            max;
  121.  
  122.     /*
  123.     * Determine the type of device from the inquiry return by the
  124.     * attach. Reject device if not of tape type. If the target 
  125.     * didn't respond to the INQUIRY command we assume that it
  126.     * just a stupid tape.
  127.     */ 
  128.     if ((devPtr->inquiryLength > 0) &&
  129.     (((ScsiInquiryData *) (devPtr->inquiryDataPtr))->type != 
  130.                             SCSI_TAPE_TYPE)) {
  131.     return DEV_NO_DEVICE;
  132.     } 
  133.     devPtr->errorProc = InitError;
  134.     /*
  135.      * Do a quick ready test on the device. This is kind of tricky because
  136.      * the error handling procedure can't be called because things aren't
  137.      * initialized yet.
  138.      */
  139.     status = DevScsiTestReady(devPtr);
  140.     if (status != SUCCESS) {
  141.     if (status == DEV_OFFLINE) {
  142.         status = DevScsiStartStopUnit(devPtr, TRUE);
  143.         if (status != SUCCESS) {
  144.         return status;
  145.         }
  146.         /*
  147.          * Give up if it still isn't ready.
  148.          */
  149.         status = DevScsiTestReady(devPtr);
  150.         if (status != SUCCESS) {
  151.         return status;
  152.         }
  153.     }
  154.     }
  155.     if (devicePtr->data == (ClientData) NIL) {
  156.     /*
  157.      * Verify that the attached device is a Tape. We do
  158.      * that by examining the Inquiry data in the ScsiDevice handle. 
  159.      */
  160.     inquiryPtr = (ScsiInquiryData *) (devPtr->inquiryDataPtr);
  161.     if ( (devPtr->inquiryLength < sizeof(ScsiInquiryData)) ||
  162.         (inquiryPtr->type != 0x1)) {
  163.         return DEV_NO_DEVICE;
  164.     }
  165.     tapePtr = &tapeData;
  166.     bzero((char *) tapePtr, sizeof(ScsiTape));
  167.     tapePtr->devPtr = devPtr;
  168.     tapePtr->state = SCSI_TAPE_CLOSED;
  169.     tapePtr->name = "SCSI Tape";
  170.     if (devicePtr->unit & DEV_SCSI_TAPE_VAR_BLOCK) {
  171.         status = DevScsiReadBlockLimits(devPtr, &min, &max);
  172.         if (status == SUCCESS) {
  173.         if (min == max) {
  174.             /*
  175.              * Device only supports fixed size blocks.
  176.              */
  177.             return DEV_NO_DEVICE;
  178.         }
  179.         tapePtr->maxBlockSize = max;
  180.         tapePtr->minBlockSize = min;
  181.         tapePtr->tapeIOProc = DevSCSITapeVariableIO;
  182.         }
  183.     } else {
  184.         int            modeSense[4];
  185.         int            size;
  186.         ScsiBlockDesc    *descPtr;
  187.         int            length;
  188.  
  189.         /*
  190.          * Do a mode sense to get the Block Descriptor, which will
  191.          * tell us the size of a logical block.
  192.          */ 
  193.         size = sizeof(modeSense);
  194.         status = DevScsiModeSense(devPtr, 0, 0, 0, 0, &size,
  195.         (char *) modeSense);
  196.         if (status != SUCCESS) {
  197.         return status;
  198.         }
  199.         descPtr = (ScsiBlockDesc *) &modeSense[1];
  200.         length = ((unsigned int) descPtr->len2 << 16) | 
  201.             ((unsigned int) descPtr->len1 << 8) |
  202.             descPtr->len0;
  203.         if (length != 0) {
  204.         } else {
  205.         /*
  206.          * A length of 0 means that the logical block size is 
  207.          * variable. In that case use the default.
  208.          */
  209.         length = SCSI_TAPE_DEFAULT_BLOCKSIZE;
  210.         }
  211.         tapePtr->blockSize = length;
  212.         tapePtr->tapeIOProc = DevSCSITapeFixedBlockIO;
  213.     }
  214.     tapePtr->specialCmdProc =  DevSCSITapeSpecialCmd;
  215.     tapePtr->statusProc = (ReturnStatus (*)()) NIL;
  216.     } else {
  217.     tapePtr = (ScsiTape *) (devicePtr->data);
  218.     }
  219.     for (i = 0; i < devNumSCSITapeTypes; i++) {
  220.     ReturnStatus    attachStatus;
  221.     attachStatus = (devSCSITapeAttachProcs[i])(devicePtr,devPtr,tapePtr);
  222.     if (attachStatus == SUCCESS) {
  223.         break;
  224.     }
  225.     }
  226.     /*
  227.      * Allocate and return the ScsiTape structure in the data field of the
  228.      * Fs_Device.
  229.      */
  230.     if ((status == SUCCESS) && (devicePtr->data == (ClientData) NIL)) { 
  231.     tapePtr = (ScsiTape *) malloc(sizeof(ScsiTape));
  232.     *tapePtr = tapeData;
  233.         devicePtr->data = (ClientData)tapePtr;
  234.     devPtr->clientData = (ClientData) tapePtr;
  235.     if (devPtr->errorProc == InitError) {
  236.         devPtr->errorProc = DevSCSITapeError;
  237.     }
  238.     }
  239.     return(status);
  240. }
  241.  
  242.  
  243. /*
  244.  *----------------------------------------------------------------------
  245.  *
  246.  * SetupCommand --
  247.  *
  248.  *    A variation on DevScsiGroup0Cmd that creates a control block
  249.  *    designed for tape drives.  SCSI tape drives read from the current
  250.  *    tape position, so there is only a block count, no offset.  There
  251.  *    is a special code that modifies the command in the tape control
  252.  *    block.  The value of the code is a function of the command and the
  253.  *    type of the tape drive (ugh.)  
  254.  *
  255.  * Results:
  256.  *    None.
  257.  *
  258.  * Side effects:
  259.  *    Set the various fields in the tape control block.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263. static void
  264. SetupCommand(devPtr, command, code, len, scsiCmdPtr)
  265.     ScsiDevice    *devPtr;    /* Scsi device for command. */
  266.     int command;        /* One of SCSI_* commands */
  267.     unsigned int code;        /* Value for "code" field of command. The code
  268.                  * field is the low 4 bits of the 2nd byte. */
  269.     unsigned int len;        /* Length of the data in bytes or blocks. */
  270.     ScsiCmd    *scsiCmdPtr;    /* Command block to fill in. */
  271. {
  272.     /*
  273.      * Length field is only 3 bytes long in scsi command block. Mask off
  274.      * the upper bits (they will be set if the number is negative).
  275.      */
  276.     len &= 0x00ffffff;
  277.     DevScsiGroup0Cmd(devPtr, command, ((code&0xf) << 16) | (len>>8),
  278.             (len & 0xff), scsiCmdPtr);
  279. }
  280.  
  281.  
  282. /*
  283.  *----------------------------------------------------------------------
  284.  *
  285.  * DevSCSITapeError --
  286.  *
  287.  *    Map SCSI errors indicated by the sense data into Sprite ReturnStatus
  288.  *    and error message. This proceedure handles two types of 
  289.  *    sense data Class 0 and class 7.
  290.  *
  291.  * Results:
  292.  *    A sprite error code.
  293.  *
  294.  * Side effects:
  295.  *    None.
  296.  *
  297.  *----------------------------------------------------------------------
  298.  */
  299. ReturnStatus
  300. DevSCSITapeError(devPtr, scsiCmdPtr)
  301.     ScsiDevice     *devPtr;    /* SCSI device that's complaining. */
  302.     ScsiCmd    *scsiCmdPtr;    /* SCSI command that had the problem. */
  303. {
  304.     unsigned char statusByte = scsiCmdPtr->statusByte;
  305.     ScsiStatus *statusPtr = (ScsiStatus *) &statusByte;
  306.     ScsiClass0Sense *sensePtr = (ScsiClass0Sense *) scsiCmdPtr->senseBuffer;
  307.     int    senseLength = scsiCmdPtr->senseLen;
  308.     ScsiTape    *tapePtr = (ScsiTape *) devPtr->clientData;
  309.     char    *name = devPtr->locationName;
  310.     char    errorString[MAX_SCSI_ERROR_STRING];
  311.     ReturnStatus    status;
  312.  
  313.     /*
  314.      * Check for status byte to see if the command returned sense
  315.      * data. If no sense data exists then we only have the status
  316.      * byte to look at.
  317.      */
  318.     if (!statusPtr->check) {
  319.     if (SCSI_RESERVED_STATUS(statusByte) || statusPtr->intStatus) {
  320.         printf("Warning: %s at %s unknown status byte 0x%x\n",
  321.            tapePtr->name, name, statusByte);
  322.         return SUCCESS;
  323.     } 
  324.     if (statusPtr->busy) {
  325.         return DEV_OFFLINE;
  326.     }
  327.     return SUCCESS;
  328.     }
  329.     if (senseLength == 0) {
  330.      printf("Warning: %s at %s error: no sense data\n", tapePtr->name,name);
  331.      return DEV_NO_SENSE;
  332.     }
  333.     if (DevScsiMapClass7Sense(senseLength, scsiCmdPtr->senseBuffer,
  334.         &status, errorString)) {
  335.     ScsiClass7Sense    *s = (ScsiClass7Sense *) scsiCmdPtr->senseBuffer;
  336.     if (errorString[0]) {
  337.          printf("Warning: %s at %s error: %s\n", tapePtr->name, name, 
  338.             errorString);
  339.     }
  340.     if (status == SUCCESS) {
  341.         if (s->fileMark) {
  342.         /*
  343.          * Hit the file mark after reading good data. Setting this 
  344.          * bit causes the next read to return zero bytes.
  345.          */
  346. #if 0
  347.         tapePtr->state |= SCSI_TAPE_AT_EOF;
  348. #endif
  349.         } else if (s->endOfMedia) {
  350.         status = DEV_END_OF_TAPE;
  351.         }
  352.     }
  353.     return status;
  354.     }
  355.     /*
  356.      * If its not a class 7 error it must be Old style sense data..
  357.      */
  358.     if (sensePtr->error == SCSI_NO_SENSE_DATA) {        
  359.     status = SUCCESS;
  360.     } else {
  361.         register int class = (sensePtr->error & 0x70) >> 4;
  362.         register int code = sensePtr->error & 0xF;
  363.         register int addr;
  364.         addr = ((unsigned int) sensePtr->highAddr << 16) |
  365.             ((unsigned int) sensePtr->midAddr << 8) |
  366.             sensePtr->lowAddr;
  367.         printf("Warning: %s at %s: Sense error (%d-%d) at <%x> ",
  368.                  tapePtr->name, name, class, code, addr);
  369.         if (devScsiNumErrors[class] > code) {
  370.         printf("%s", devScsiErrors[class][code]);
  371.         }
  372.         printf("\n");
  373.         status = DEV_INVALID_ARG;
  374.     } 
  375.     return(status);
  376. }
  377.  
  378.  
  379. /*
  380.  *----------------------------------------------------------------------
  381.  *
  382.  * DevSCSITapeSpecialCmd --
  383.  *
  384.  *    Performance a special tape command on a SCSI Tape drive. This 
  385.  *    routine should work on any SCSI Tape drive adhering to the SCSI
  386.  *    common command set.
  387.  *
  388.  * Results:
  389.  *    The sprite return status.
  390.  *
  391.  * Side effects:
  392.  *    Command dependent.
  393.  *
  394.  *----------------------------------------------------------------------
  395.  */
  396.  
  397. ReturnStatus
  398. DevSCSITapeSpecialCmd(tapePtr, command, count)
  399.     ScsiTape    *tapePtr;    /* Target drive for command. */
  400.     int        command;    /* Command to be performed. */
  401.     int        count;        /* Argument to command. */
  402. {
  403.     ReturnStatus status;
  404.     ScsiCmd     scsiTapeCmd;
  405.     unsigned int    code;
  406.     int            amountTransferred;
  407.     int        scsiCmd = 0;
  408.     Boolean    group0 = TRUE;
  409.  
  410.    code = 0;
  411.    switch (command) {
  412.     case IOC_TAPE_SKIP_FILES:
  413.     case IOC_TAPE_SKIP_BLOCKS: 
  414.     scsiCmd = SCSI_SPACE;
  415.     code = (command == IOC_TAPE_SKIP_FILES) ? 1 : 0;
  416.     break;
  417.     case IOC_TAPE_REWIND:
  418.     scsiCmd = SCSI_REWIND;
  419.     count = 0;
  420.     break;
  421.     case IOC_TAPE_WEOF:
  422.     scsiCmd = SCSI_WRITE_EOF;
  423.     break;
  424.     case IOC_TAPE_ERASE:
  425.     scsiCmd = SCSI_ERASE_TAPE;
  426.     count = 0;
  427.     break;
  428.     case IOC_TAPE_NO_OP:
  429.     scsiCmd = SCSI_TEST_UNIT_READY;
  430.     count = 0;
  431.     break;
  432.     case IOC_TAPE_RETENSION:
  433.     return DEV_INVALID_ARG;
  434.     case IOC_TAPE_SKIP_EOD:
  435.     scsiCmd = SCSI_SPACE;
  436.     code = 3;
  437.     break;
  438.     case IOC_TAPE_GOTO_BLOCK: {
  439.     ScsiLocateCmd    *cmdPtr = (ScsiLocateCmd *) scsiTapeCmd.commandBlock;
  440.     scsiTapeCmd.commandBlockLen = sizeof(*cmdPtr);
  441.     bzero((char *) cmdPtr, sizeof(*cmdPtr));
  442.     group0 = FALSE;
  443.     cmdPtr->command = SCSI_LOCATE;
  444.     cmdPtr->unitNumber = tapePtr->devPtr->LUN;
  445.     cmdPtr->addr3 = (count & 0xff000000) >> 24;
  446.     cmdPtr->addr2 = (count & 0x00ff0000) >> 16;
  447.     cmdPtr->addr1 = (count & 0x0000ff00) >> 8;
  448.     cmdPtr->addr0 = (count & 0x000000ff);
  449.     break;
  450.     }
  451.     case IOC_TAPE_LOAD: 
  452.     case IOC_TAPE_UNLOAD:
  453.     scsiCmd = SCSI_LOAD_UNLOAD;
  454.     count = (command == IOC_TAPE_LOAD) ? 1 : 0;
  455.     break;
  456.     case IOC_TAPE_PREVENT_REMOVAL:
  457.     case IOC_TAPE_ALLOW_REMOVAL: {
  458.     ScsiPreventAllowCmd    *cmdPtr;
  459.     cmdPtr = (ScsiPreventAllowCmd *) scsiTapeCmd.commandBlock;
  460.     scsiTapeCmd.commandBlockLen = sizeof(*cmdPtr);
  461.     bzero((char *) cmdPtr, sizeof(*cmdPtr));
  462.     group0 = FALSE;
  463.     cmdPtr->command = SCSI_PREVENT_ALLOW;
  464.     if (command == IOC_TAPE_PREVENT_REMOVAL) {
  465.         cmdPtr->prevent = 1;
  466.     }
  467.     break;
  468.     }
  469.     default:
  470.     scsiCmd = 0;
  471.     panic("DevSCSITapeSpecialCmd: Unknown command %d\n", command);
  472.     }
  473.     if (group0) {
  474.     SetupCommand(tapePtr->devPtr, scsiCmd, code, (unsigned)count, 
  475.             &scsiTapeCmd);
  476.     }
  477.     scsiTapeCmd.buffer = (char *) 0;
  478.     scsiTapeCmd.bufferLen = 0;
  479.     scsiTapeCmd.dataToDevice = FALSE;
  480.     status = DevScsiSendCmdSync(tapePtr->devPtr, &scsiTapeCmd,
  481.                 &amountTransferred);
  482.     return(status);
  483.  
  484. }
  485.  
  486.  
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * DevSCSITapeVariableIO --
  491.  *
  492.  *      Low level routine to read or write an SCSI tape device using a
  493.  *    variable size block format.   Each IO involves some number of
  494.  *    bytes.
  495.  *
  496.  * Results:
  497.  *    The Sprite return status.
  498.  *
  499.  * Side effects:
  500.  *    Tape is written or read.
  501.  *
  502.  *----------------------------------------------------------------------
  503.  */
  504. ReturnStatus
  505. DevSCSITapeVariableIO(tapePtr,command, buffer, countPtr)
  506.     register ScsiTape *tapePtr;     /* State info for the tape */
  507.     int command;            /* SCSI_READ, SCSI_WRITE, etc. */
  508.     char *buffer;            /* Target buffer */
  509.     int *countPtr;            /* In/Out byte count. */
  510. {
  511.     ReturnStatus status;
  512.     ScsiCmd     scsiTapeCmd;
  513.  
  514.     if (((*countPtr < tapePtr->minBlockSize) && (*countPtr != 0)) ||
  515.     (*countPtr > tapePtr->maxBlockSize)) {
  516.     return DEV_INVALID_ARG;
  517.     }
  518.     /* 
  519.      * Setup the command, a code value of zero means variable block.
  520.      */
  521.     SetupCommand(tapePtr->devPtr, command, 0,  (unsigned)*countPtr & 0xffff, 
  522.         &scsiTapeCmd);
  523.     scsiTapeCmd.buffer = buffer;
  524.     scsiTapeCmd.bufferLen = *countPtr;
  525.     scsiTapeCmd.dataToDevice = (command == SCSI_WRITE);
  526.     status = DevScsiSendCmdSync(tapePtr->devPtr, &scsiTapeCmd, countPtr);
  527.  
  528.     return(status);
  529. }
  530.  
  531.  
  532. /*
  533.  *----------------------------------------------------------------------
  534.  *
  535.  * DevSCSITapeFixedBlockIO --
  536.  *
  537.  *      Low level routine to read or write an SCSI tape device using a
  538.  *    fixed size block format.   Each IO involves one or more tape blocks 
  539.  *    and must be  multiples of the underlying device block size.
  540.  *
  541.  * Results:
  542.  *    The Sprite return status.
  543.  *
  544.  * Side effects:
  545.  *    Tape is written or read.
  546.  *
  547.  *----------------------------------------------------------------------
  548.  */
  549. ReturnStatus
  550. DevSCSITapeFixedBlockIO(tapePtr, command, buffer, countPtr)
  551.     register ScsiTape *tapePtr;     /* State info for the tape */
  552.     int command;            /* SCSI_READ, SCSI_WRITE, etc. */
  553.     char *buffer;            /* Target buffer */
  554.     int *countPtr;            /* In/Out byte count. */
  555. {
  556.     ReturnStatus status;
  557.     ScsiCmd     scsiTapeCmd;
  558.     int        lengthInBlocks;
  559.  
  560.    /*
  561.      * For simplicity reads and writes that are multiple of the block size
  562.      * are rejected.
  563.      */
  564.     if ((*countPtr % (tapePtr->blockSize)) != 0) {
  565.     *countPtr = 0;
  566.     return DEV_INVALID_ARG;
  567.     }
  568.     lengthInBlocks = *countPtr / tapePtr->blockSize;
  569.     /*
  570.      * Set up the command with a code value of 1 meaning fixed block.
  571.      */
  572.     SetupCommand(tapePtr->devPtr, command, 1, (unsigned)lengthInBlocks,
  573.          &scsiTapeCmd);
  574.     scsiTapeCmd.buffer = buffer;
  575.     scsiTapeCmd.bufferLen = *countPtr;
  576.     scsiTapeCmd.dataToDevice = (command == SCSI_WRITE);
  577.     status = DevScsiSendCmdSync(tapePtr->devPtr, &scsiTapeCmd, countPtr);
  578.  
  579.     return(status);
  580. }
  581.  
  582. /*
  583.  *----------------------------------------------------------------------
  584.  *
  585.  * DevSCSITapeOpen --
  586.  *
  587.  *    Open a SCSI tape drive as a file.  This routine verifies the
  588.  *    drives existance and sets any special mode flags.
  589.  *
  590.  * Results:
  591.  *    SUCCESS if the tape is on-line.
  592.  *
  593.  * Side effects:
  594.  *    None.
  595.  *
  596.  *----------------------------------------------------------------------
  597.  */
  598. /* ARGSUSED */
  599. ReturnStatus
  600. DevSCSITapeOpen(devicePtr, useFlags, token, flagsPtr)
  601.     Fs_Device *devicePtr;    /* Device info, unit number etc. */
  602.     int useFlags;        /* Flags from the stream being opened */
  603.     Fs_NotifyToken token;    /* Call-back token for input, unused here */
  604.     int        *flagsPtr;    /* OUT: Device flags. */
  605. {
  606.     ReturnStatus status;
  607.     ScsiDevice *devPtr;
  608.     ScsiTape *tapePtr;
  609.  
  610.     tapePtr = (ScsiTape *) (devicePtr->data);
  611.     if (tapePtr == (ScsiTape *) NIL) {
  612.     /*
  613.      * Ask the HBA to set up the path to the device with FIFO ordering
  614.      * of requests.
  615.      */
  616.     devPtr = DevScsiAttachDevice(devicePtr, DEV_QUEUE_FIFO_INSERT);
  617.     if (devPtr == (ScsiDevice *) NIL) {
  618.         return DEV_NO_DEVICE;
  619.     }
  620.     } else { 
  621.     /*
  622.      * If the tapePtr is already attached to the device it must be
  623.      * busy.
  624.      */
  625.      return(FS_FILE_BUSY);
  626.     }
  627.     status = InitTapeDevice(devicePtr, devPtr);
  628.     return(status);
  629. }
  630.  
  631. /*
  632.  *----------------------------------------------------------------------
  633.  *
  634.  * DevSCSITapeRead --
  635.  *
  636.  *    Read from a raw SCSI Tape.  The offset is ignored because
  637.  *    you can't seek the SCSI tape drive, only rewind it.
  638.  *
  639.  * Results:
  640.  *    The return status of the read.
  641.  *
  642.  * Side effects:
  643.  *    The process will sleep waiting for the I/O to complete.
  644.  *
  645.  *----------------------------------------------------------------------
  646.  */
  647.  
  648. /*ARGSUSED*/
  649. ReturnStatus
  650. DevSCSITapeRead(devicePtr, readPtr, replyPtr)
  651.     Fs_Device *devicePtr;    /* Handle for raw SCSI tape device */
  652.     Fs_IOParam    *readPtr;    /* Read parameter block */
  653.     Fs_IOReply    *replyPtr;    /* Return length and signal */ 
  654. {
  655.     ReturnStatus error;    
  656.     ScsiTape *tapePtr;
  657.     int    totalTransfer;
  658.     int transferSize;
  659.     int    maxXfer;
  660.  
  661.     tapePtr = (ScsiTape *)(devicePtr->data);
  662. #if 0
  663.     if (tapePtr->state & SCSI_TAPE_AT_EOF) {
  664.     /*
  665.      * Force the use of the SKIP_FILES control to get past the end of
  666.      * the file on tape.
  667.      */
  668.     replyPtr->length = 0;
  669.     return(SUCCESS);
  670.     }
  671. #endif
  672.     /*
  673.      * Break up the IO into piece the device/HBA can handle.
  674.      */
  675.     error = SUCCESS;
  676.     maxXfer = tapePtr->devPtr->maxTransferSize;
  677.     totalTransfer = 0;
  678.     while((readPtr->length > 0) && (error == SUCCESS)) {  
  679.     int    byteCount;
  680.     transferSize = (readPtr->length > maxXfer) ? maxXfer : readPtr->length;
  681.     byteCount = transferSize;
  682.     error = (tapePtr->tapeIOProc)(tapePtr, SCSI_READ,
  683.                   readPtr->buffer + totalTransfer, &byteCount);
  684.     /*
  685.      * A short read implies we hit end of file or end of tape. 
  686.      */
  687.     totalTransfer += byteCount;
  688.     readPtr->length -= byteCount;
  689.     if (byteCount < transferSize) {
  690.         break;
  691.     }
  692.     }
  693.     replyPtr->length = totalTransfer;
  694.     /*
  695.      * Special check against funky end-of-file situations.  The Emulex tape
  696.      * doesn't compute a correct residual when it hits the file mark
  697.      * on the tape.
  698.      */
  699.     if (error == DEV_END_OF_TAPE) {
  700.     replyPtr->length = 0;
  701.     error = SUCCESS;
  702.     }
  703.     return(error);
  704. }
  705.  
  706. /*
  707.  *----------------------------------------------------------------------
  708.  *
  709.  * DevSCSITapeWrite --
  710.  *
  711.  *    Write to a raw SCSI tape.
  712.  *
  713.  * Results:
  714.  *    A Sprite error code.
  715.  *
  716.  * Side effects:
  717.  *    None.
  718.  *
  719.  *----------------------------------------------------------------------
  720.  */
  721.  
  722. /*ARGSUSED*/
  723. ReturnStatus
  724. DevSCSITapeWrite(devicePtr, writePtr, replyPtr)
  725.     Fs_Device *devicePtr;    /* Handle of raw tape device */
  726.     Fs_IOParam    *writePtr;    /* Standard write parameter block */
  727.     Fs_IOReply    *replyPtr;    /* Return length and signal */
  728. {
  729.     ReturnStatus error;    
  730.     ScsiTape *tapePtr;
  731.     int totalTransfer;
  732.     int transferSize;
  733.     int    maxXfer;
  734.  
  735.     tapePtr = (ScsiTape *)(devicePtr->data);
  736.     /*
  737.      * Break up the IO into piece the device/HBA can handle.
  738.      */
  739.     error = SUCCESS;
  740.     maxXfer = tapePtr->devPtr->maxTransferSize;
  741.     totalTransfer = 0;
  742.     while((writePtr->length > 0) && (error == SUCCESS)) {  
  743.     int    byteCount;
  744.     transferSize = (writePtr->length > maxXfer) ? maxXfer : writePtr->length;
  745.     byteCount = transferSize;
  746.     error = (tapePtr->tapeIOProc)(tapePtr, SCSI_WRITE,
  747.                   writePtr->buffer + totalTransfer, &byteCount);
  748.     /*
  749.      * A short write implies we hit end of tape. 
  750.      */
  751.     totalTransfer += byteCount;
  752.     writePtr->length -= transferSize;
  753.     if (byteCount < transferSize) {
  754.         break;
  755.     }
  756.     }
  757.     replyPtr->length = totalTransfer;
  758.     if (error == SUCCESS) {
  759.     tapePtr->state |= SCSI_TAPE_WRITTEN;
  760.     }
  761.     return(error);
  762. }
  763.  
  764. /*
  765.  *----------------------------------------------------------------------
  766.  *
  767.  * DevSCSITapeIOControl --
  768.  *
  769.  *    Do a special operation on a raw SCSI Tape.
  770.  *
  771.  * Results:
  772.  *    None.
  773.  *
  774.  * Side effects:
  775.  *    None.
  776.  *
  777.  *----------------------------------------------------------------------
  778.  */
  779. /*ARGSUSED*/
  780. ReturnStatus
  781. DevSCSITapeIOControl(devicePtr, ioctlPtr, replyPtr)
  782.     Fs_Device *devicePtr;
  783.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  784.     Fs_IOReply *replyPtr;    /* Size of outBuffer and returned signal */
  785. {
  786.     ScsiTape *tapePtr;
  787.     ReturnStatus status = SUCCESS;
  788.     int        fmtStatus;
  789.     int        inSize;
  790.     int        outSize;
  791.  
  792.     tapePtr = (ScsiTape *)(devicePtr->data);
  793.      if ((ioctlPtr->command & ~0xffff) == IOC_SCSI) {
  794.      status = DevScsiIOControl(tapePtr->devPtr, ioctlPtr, replyPtr);
  795.      return status;
  796.  
  797.      }
  798.  
  799.     switch(ioctlPtr->command) {
  800.     case IOC_REPOSITION: {
  801.         Ioc_RepositionArgs repoArgs;
  802.         inSize = ioctlPtr->inBufSize;
  803.         outSize = sizeof(Ioc_RepositionArgs);
  804.         fmtStatus = Fmt_Convert("w*", ioctlPtr->format, &inSize,
  805.         ioctlPtr->inBuffer, mach_Format, &outSize, (Address) &repoArgs);
  806.         if (fmtStatus != 0) {
  807.         printf("Format of IOC_REPOSITION parameter failed, 0x%x\n",
  808.             fmtStatus);
  809.         return DEV_INVALID_ARG;
  810.         }
  811.         if (outSize < sizeof(Ioc_RepositionArgs)) {
  812.         return DEV_INVALID_ARG;
  813.         }
  814.         switch (repoArgs.base) {
  815.         case IOC_BASE_ZERO:
  816.             if (repoArgs.offset != 0) {
  817.             return(DEV_INVALID_ARG);
  818.             }
  819.             status = (tapePtr->specialCmdProc)(tapePtr,
  820.                           IOC_TAPE_REWIND, 1);
  821.             break;
  822.         case IOC_BASE_CURRENT:
  823.             status = DEV_INVALID_ARG;
  824.             break;
  825.         case IOC_BASE_EOF:
  826.             if (repoArgs.offset != 0) {
  827.             status = DEV_INVALID_ARG;
  828.             } else if ((tapePtr->state & SCSI_TAPE_WRITTEN) == 0) {
  829.             /*
  830.              * If not atlready at the end of the tape by writing,
  831.              * space to the end of the current file.
  832.              */
  833.             status = (tapePtr->specialCmdProc)(tapePtr, 
  834.                            IOC_TAPE_SKIP_FILES, 1);
  835.             }
  836.             break;
  837.         }
  838.         tapePtr->state &= ~SCSI_TAPE_WRITTEN;
  839.         break;
  840.     }
  841.     case IOC_TAPE_COMMAND: {
  842.         Dev_TapeCommand cmd;
  843.         inSize = ioctlPtr->inBufSize;
  844.         outSize = sizeof(Dev_TapeCommand);
  845.         fmtStatus = Fmt_Convert("w*", ioctlPtr->format, &inSize,
  846.             ioctlPtr->inBuffer, mach_Format, &outSize, (Address) &cmd);
  847.         if (fmtStatus != 0) {
  848.         printf("Format of IOC_TAPE_COMMAND parameter failed, 0x%x\n",
  849.             fmtStatus);
  850.         return DEV_INVALID_ARG;
  851.         }
  852.         if (outSize < sizeof(Dev_TapeCommand)) {
  853.         return(DEV_INVALID_ARG);
  854.         }
  855.         tapePtr->state &= ~SCSI_TAPE_WRITTEN;
  856.         switch (cmd.command) {
  857.         case IOC_TAPE_WEOF: {
  858.             status = (tapePtr->specialCmdProc)(tapePtr, IOC_TAPE_WEOF,
  859.                             cmd.count);
  860.             break;
  861.         }
  862.         case IOC_TAPE_RETENSION: {
  863.             status = (tapePtr->specialCmdProc)(tapePtr,
  864.                           IOC_TAPE_RETENSION, 1);
  865.             break;
  866.         }
  867.         case IOC_TAPE_OFFLINE:
  868.         case IOC_TAPE_REWIND: {
  869.             status = (tapePtr->specialCmdProc)(tapePtr,
  870.                           IOC_TAPE_REWIND, 1);
  871.             break;
  872.         }
  873.         case IOC_TAPE_SKIP_BLOCKS: {
  874.             status = (tapePtr->specialCmdProc)(tapePtr, 
  875.                     IOC_TAPE_SKIP_BLOCKS, cmd.count);
  876.             break;
  877.         case IOC_TAPE_SKIP_FILES:
  878.             status = (tapePtr->specialCmdProc)(tapePtr, 
  879.                     IOC_TAPE_SKIP_FILES,  cmd.count);
  880.             break;
  881.         }
  882.         case IOC_TAPE_BACKUP_BLOCKS:
  883.         case IOC_TAPE_BACKUP_FILES:
  884.             status = DEV_INVALID_ARG;
  885.             break;
  886.         case IOC_TAPE_ERASE: {
  887.             status = (tapePtr->specialCmdProc)(tapePtr, 
  888.                             IOC_TAPE_ERASE,1);
  889.             break;
  890.         }
  891.         case IOC_TAPE_NO_OP: {
  892.             status = (tapePtr->specialCmdProc)(tapePtr, 
  893.                               IOC_TAPE_NO_OP,1);
  894.             break;
  895.         }
  896.         case IOC_TAPE_SKIP_EOD: {
  897.             status = (tapePtr->specialCmdProc)(tapePtr, 
  898.                               IOC_TAPE_SKIP_EOD,1);
  899.             break;
  900.         }
  901.         case IOC_TAPE_GOTO_BLOCK: {
  902.             status = (tapePtr->specialCmdProc)(tapePtr, 
  903.                       IOC_TAPE_GOTO_BLOCK, cmd.count);
  904.             break;
  905.         }
  906.         case IOC_TAPE_LOAD:
  907.         case IOC_TAPE_UNLOAD: 
  908.         case IOC_TAPE_PREVENT_REMOVAL:
  909.         case IOC_TAPE_ALLOW_REMOVAL: {
  910.             status = (tapePtr->specialCmdProc)(tapePtr, 
  911.                       cmd.command, cmd.count);
  912.             break;
  913.         }
  914.         default:
  915.             status = DEV_INVALID_ARG;
  916.         }
  917.         break;
  918.     }
  919.     case IOC_TAPE_STATUS: {
  920.         Dev_TapeStatus        tapeStatus;
  921.         ScsiReadPositionResult    position;
  922.         Boolean            readPosition = 1;
  923.  
  924.         bzero((char *) &position, sizeof(position));
  925.         bzero((char *) &tapeStatus, sizeof(tapeStatus));
  926.         tapeStatus.type = tapePtr->type;
  927.         tapeStatus.blockSize = tapePtr->blockSize;
  928.         tapeStatus.position = -1;
  929.         tapeStatus.remaining = -1;
  930.         tapeStatus.dataError= -1;
  931.         tapeStatus.readWriteRetry = -1;
  932.         tapeStatus.trackingRetry = -1;
  933.         tapeStatus.bufferedMode = -1;
  934.         tapeStatus.speed = -1;
  935.         tapeStatus.density = -1;
  936.         if (tapePtr->statusProc != (ReturnStatus (*)()) NIL) {
  937.         status = (tapePtr->statusProc)(tapePtr, &tapeStatus, 
  938.             &readPosition);
  939.         }
  940.         if (readPosition) {
  941.         status = DevScsiReadPosition(tapePtr->devPtr, 0, &position);
  942.         if ((status == SUCCESS) && (position.bpu == 0)) {
  943.             tapeStatus.position = 
  944.                 ((unsigned int) position.firstBlock3 << 24) |
  945.                 ((unsigned int) position.firstBlock2 << 16) |
  946.                 ((unsigned int) position.firstBlock1 << 8) |
  947.                 (position.firstBlock0);
  948.         }
  949.         }
  950.         inSize = sizeof(Dev_TapeStatus);
  951.         outSize = ioctlPtr->outBufSize;
  952.         fmtStatus = Fmt_Convert("w*", mach_Format, &inSize,
  953.             (Address) &tapeStatus, ioctlPtr->format, &outSize, 
  954.             (Address) ioctlPtr->outBuffer);
  955.         if (fmtStatus != 0) {
  956.         if (fmtStatus != FMT_OUTPUT_TOO_SMALL) {
  957.             printf("Format of IOC_TAPE_STATUS parameter failed, 0x%x\n",
  958.             fmtStatus);
  959.         }
  960.         return DEV_INVALID_ARG;
  961.         }
  962.         return status;
  963.     }
  964.         /*
  965.          * No tape specific bits are set this way.
  966.          */
  967.     case    IOC_GET_FLAGS:
  968.     case    IOC_SET_FLAGS:
  969.     case    IOC_SET_BITS:
  970.     case    IOC_CLEAR_BITS:
  971.         return(SUCCESS);
  972.  
  973.     case    IOC_GET_OWNER:
  974.     case    IOC_SET_OWNER:
  975.         return(GEN_NOT_IMPLEMENTED);
  976.  
  977.     case    IOC_TRUNCATE:
  978.         /*
  979.          * Could make this to an erase tape...
  980.          */
  981.         return(GEN_INVALID_ARG);
  982.  
  983.     case    IOC_LOCK:
  984.     case    IOC_UNLOCK:
  985.         return(GEN_NOT_IMPLEMENTED);
  986.  
  987.     case    IOC_NUM_READABLE:
  988.         return(GEN_NOT_IMPLEMENTED);
  989.  
  990.     case    IOC_MAP:
  991.         return(GEN_NOT_IMPLEMENTED);
  992.         
  993.     default:
  994.         return(GEN_INVALID_ARG);
  995.     }
  996.     return(status);
  997. }
  998.  
  999. /*
  1000.  *----------------------------------------------------------------------
  1001.  *
  1002.  * DevSCSITapeClose --
  1003.  *
  1004.  *    Close a raw SCSI tape file.  This checks the unit number to
  1005.  *    determine if the tape should be rewound.  Units 0 and 8
  1006.  *    are rewind always, units 1 and 9 are no-rewind..
  1007.  *
  1008.  * Results:
  1009.  *    None.
  1010.  *
  1011.  * Side effects:
  1012.  *    None.
  1013.  *
  1014.  *----------------------------------------------------------------------
  1015.  */
  1016. /*ARGSUSED*/
  1017. ReturnStatus
  1018. DevSCSITapeClose(devicePtr, useFlags, openCount, writerCount)
  1019.     Fs_Device    *devicePtr;
  1020.     int        useFlags;    /* FS_READ | FS_WRITE */
  1021.     int        openCount;    /* Number of times device open. */
  1022.     int        writerCount;    /* Number of times device open for writing. */
  1023. {
  1024.     ScsiTape *tapePtr;
  1025.     ReturnStatus status = SUCCESS;
  1026.  
  1027.     tapePtr = (ScsiTape *)(devicePtr->data);
  1028.     if (openCount > 0) {
  1029.     return(SUCCESS);
  1030.     }
  1031.     if (tapePtr->state & SCSI_TAPE_WRITTEN) {
  1032.     /*
  1033.      * Make sure an end-of-file mark is at the end of the file on tape.
  1034.      */
  1035.     status = (tapePtr->specialCmdProc)(tapePtr, IOC_TAPE_WEOF,1);
  1036.     }
  1037.     if (status == SUCCESS) {
  1038.     /*
  1039.      * If the "no rewind" flag is not set then rewind the device.
  1040.      */
  1041.     if (!(devicePtr->unit & DEV_SCSI_TAPE_NO_REWIND)) {
  1042.         status = (tapePtr->specialCmdProc)(tapePtr, IOC_TAPE_REWIND,1);
  1043.     }
  1044.     }
  1045.     (void) DevScsiReleaseDevice(tapePtr->devPtr);
  1046.     free((char *)tapePtr);
  1047.     devicePtr->data = (ClientData) NIL;
  1048.     return(status);
  1049. }
  1050.  
  1051.